package com.smile.frame.springbootsatoken.config;


import cn.hutool.core.util.StrUtil;
import com.smile.frame.springbootsatoken.config.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * 安全拦截
 *
 * @author LGC
 */
@Slf4j
@Component
@Order(1)
public class SecurityInterceptor implements HandlerInterceptor {

    @Resource
    private RedisService redisService;

    @Resource
    private SecurityProperties securityProperties;

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("安全拦截");
        List<String> defaultIgnoreUrls = securityProperties.getDefaultIgnoreUrls();
        List<String> ignoredUrls = securityProperties.getIgnoredUrls();
        System.out.println("servletPath:\t\t\t" + request.getServletPath());
        System.out.println("contextPath:\t\t\t" + request.getContextPath());
        System.out.println("contextPath2:\t\t\t" + request.getServletContext().getContextPath());
        System.out.println("pageInfo:\t\t\t" + request.getPathInfo());
        System.out.println("uri:\t\t\t" + request.getRequestURI());
        System.out.println("url:\t\t\t" + request.getRequestURL());
        System.out.println("realPath:\t\t\t" + request.getServletContext().getRealPath("/"));
        // 路径忽略过滤认证
        boolean pathMatch = false;
        for (String url : defaultIgnoreUrls) {
            if (pathMatcher.match(url, request.getRequestURI())) {
                pathMatch = true;
                break;
            }
        }
        for (String url : ignoredUrls) {
            if (pathMatcher.match(url, request.getRequestURI())) {
                pathMatch = true;
                break;
            }
        }
        if (pathMatch) {
            return true;
        }

        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 忽略注解过滤认证
            IgnoreAuth ignoreAuth = handlerMethod.getMethod().getAnnotation(IgnoreAuth.class);
            if (null == ignoreAuth) {
                ignoreAuth = handlerMethod.getMethod().getDeclaringClass().getAnnotation(IgnoreAuth.class);
            }
            if (ignoreAuth != null) {
                return true;
            }

            // 登录校验
            String platformType = request.getHeader(TokenConstants.PLATFORM_TYPE);
            String token = request.getHeader(TokenConstants.AUTHORIZATION_KEY);
            log.info("platformType:{},token:{}", platformType, token);

            if (StrUtil.isBlank(token)) {
                throw new Exception("token为空");
            }
            String tokenKey = "tafb:auth:" + TokenConstants.LOGIN_TYPE_ADMIN + ":token:" + token;
            Object loginId = redisService.get(tokenKey);
            if (loginId == null) {
                throw new Exception("token失效过期");
            }

            // 权限校验
            Perm perm = handlerMethod.getMethod().getAnnotation(Perm.class);
            if (null == perm) {
                perm = handlerMethod.getMethod().getDeclaringClass().getAnnotation(Perm.class);
            }
            List<String> keys = new ArrayList<>();
            keys.add("get");
            if (perm != null) {
                String[] value = perm.value();
                boolean permMatch = Arrays.stream(value).anyMatch(s -> keys.contains(s));
                if (!permMatch) {
                    throw new Exception("权限不足" + perm.value());
                }
            }
        }
        return true;
    }
}
